using System;
using System.Text;
using System.Data;
using System.Collections;
using RandomRat.Data;

namespace RandomRat {
	
	public enum SummaryType{ AbbreviatedNames, FullNames }


	public class CriteriaFormState {
		public string CriteriaID;
		
		public string Slots;			 // The number of types in a set
		public string Sets;
		public string[] Types;			 // Types in the set
		public string SuccessionTol;	 // The mininum number of sucsessive types alowed
		public string EveryOtherTol;	 // The minimum number of every other groupings alowed 
		// eg: {..., "1","2","1","2", ...} represents a 2 every other groupings
		public ArrayList advancedPatternRules; 
		
		public bool checkedSuccessionTol;
		public bool checkedEveryOtherTol;
		public bool checkedPatternRules;
		public bool checkedForceEqualTypes; // Determines if sets containe an equal number of each type

		

		public CriteriaFormState() {
			advancedPatternRules = new ArrayList(10);
		}

		public SetArguments ToSetArguments() {
			SetArguments setArgs = new SetArguments();
	
			try {
				setArgs.Slots = int.Parse(this.Slots);
			} catch {
				setArgs.Slots = -1;
			}

			setArgs.forceEqualTypes = this.checkedForceEqualTypes;

			try {
				setArgs.SuccessionTol = int.Parse(this.SuccessionTol);
			} catch {
				setArgs.SuccessionTol = -1;
			}

			setArgs.Types = this.Types;

			int everyOther = -1;
			try {
				everyOther = int.Parse(this.EveryOtherTol);
			} catch {}

			int i;
			if (everyOther != -1) {
				setArgs.patternRules = new int[1 + this.advancedPatternRules.Count][];
				setArgs.patternRules[0] = new int[2] {2, everyOther};
				i = 1;
			} else {
				setArgs.patternRules = new int[this.advancedPatternRules.Count][];
				i = 0;
			}

			foreach (int[] rule in advancedPatternRules) {
				setArgs.patternRules[i++] = rule;
			}

			return setArgs;
		}

		
		public override string ToString() {
			StringBuilder sb = new StringBuilder();
			// CriteriaID  Slots=10FET  Types=X, Y, Z  SuccessionTol=XX  EveryOtherTol=XX  AP(2,5)(3,5)  
			// checkedPatternRules  checkedSuccessionTol  checkedEveryOtherTol
			string sepSpace = "  ";
			
			// CriteriaID (Messes up equality test when critiera is renamed)
			//sb.Append(CriteriaID);
			//sb.Append(sepSpace);

			// Slots=10FET  
			sb.Append("Slots=" + Slots);
			if (checkedForceEqualTypes) sb.Append("FET");

			sb.Append(sepSpace);

			// Types=X, Y, Z  
			if (Types != null && Types.Length > 0) {
				sb.Append("Types=");
				foreach (string type in Types) {
					sb.Append(type + ", ");
				}
			
				sb.Append(sepSpace);
			}

			// SuccessionTol=XX
			sb.Append("SuccessionTol=" + SuccessionTol);
			sb.Append(sepSpace);

			// EveryOtherTol=XX
			sb.Append("EveryOtherTol==" + EveryOtherTol);
			sb.Append(sepSpace);
			
			// AP(2,5)(3,5)
			if (advancedPatternRules.Count > 0) {
				sb.Append("AP");

				foreach (int[] rule in advancedPatternRules) {
					sb.Append("(" + rule[0].ToString() + "," + rule[1].ToString() + ")");
				}

				sb.Append(sepSpace);
			}

			// checkedPatternRules  checkedSuccessionTol  checkedEveryOtherTol
			if (checkedPatternRules) sb.Append("checkedPatternRules");
			sb.Append(sepSpace);
			if (checkedSuccessionTol) sb.Append("checkedSuccessionTol");
			sb.Append(sepSpace);
			if (checkedEveryOtherTol) sb.Append("checkedEveryOtherTol");


			return sb.ToString();
		}



		public static bool IsBlank(CriteriaFormState formState) {
			if (formState.Slots == "" &&
				formState.SuccessionTol == "" &&
				formState.EveryOtherTol == "" &&
				formState.advancedPatternRules.Count == 0 &&
				!formState.checkedForceEqualTypes) {

				return true;
			} else {
				return false;
			}
		}

		

		public static string GetSummary(CriteriaFormState formSate, SummaryType summaryType, bool showCriteriaName) {
			StringBuilder sb = new StringBuilder();
			
			// Criteria name:  'Unlabled'
			if (showCriteriaName) {
				sb.Append("Criteria name:\t'");
				sb.Append(formSate.CriteriaID + "'");
				sb.Append("\n");
			}


			//Number in set:  10  (Forced equal types)
			if (formSate.Slots != "") {
				if (showCriteriaName) sb.Append("\n");
				sb.Append("Number in set:\t");
				sb.Append(formSate.Slots);
				if (formSate.checkedForceEqualTypes) { 
					if (summaryType == SummaryType.AbbreviatedNames) {
						sb.Append("  (equal types)");
					} else if (summaryType == SummaryType.FullNames) {
						sb.Append("  (force equal types)");
					}
				}
				sb.Append("\n");
			}

			/// Element types:	A
			///					B
			///					C
			if (formSate.Types.Length > 0) {
				sb.Append("\n");
				sb.Append("Element types:\t");
				sb.Append(formSate.Types[0]);
				for (int i = 1; i < formSate.Types.Length; i++) {
					sb.Append("\n\t\t" + formSate.Types[i]);
				}
				sb.Append("\n");
			}

			// Succession tolerance:  3
			if (formSate.checkedSuccessionTol && formSate.SuccessionTol != "") {
				sb.Append("\n");

				if (summaryType == SummaryType.AbbreviatedNames) {
					sb.Append("Succession tol:\t");
				} else if (summaryType == SummaryType.FullNames) {
					sb.Append("Succession tolerance:\t");
				}

				sb.Append(formSate.SuccessionTol);
				if (!formSate.checkedEveryOtherTol) {
					sb.Append("\n");
				}
			}

			// Succession tolerance:  3
			if (formSate.checkedEveryOtherTol && formSate.EveryOtherTol != "") {
				sb.Append("\n");
				
				if (summaryType == SummaryType.AbbreviatedNames) {
					sb.Append("Every-other tol:\t");
				} else if (summaryType == SummaryType.FullNames) {
					sb.Append("Every-other tolerance:\t");
				}

				sb.Append(formSate.EveryOtherTol);
				sb.Append("\n");
			}
				

			/// advanced pattern tolerance:	3, 1
			///								4, 2
			if (formSate.checkedPatternRules && formSate.advancedPatternRules.Count > 0) {
				if (summaryType == SummaryType.AbbreviatedNames) {
					sb.Append("\nAdv pattern tol:\t");
				} else if (summaryType == SummaryType.FullNames) {
					sb.Append("\nAdvanced pattern tolerance:\t");
				}

				sb.Append(((int[])formSate.advancedPatternRules[0])[0].ToString() + ", " +
					((int[])formSate.advancedPatternRules[0])[1].ToString());
				
				for (int i = 1; i < formSate.advancedPatternRules.Count; i++) {

					if (summaryType == SummaryType.AbbreviatedNames) {
						sb.Append("\n\t\t" + ((int[])formSate.advancedPatternRules[i])[0].ToString() + ", " +
											 ((int[])formSate.advancedPatternRules[i])[1].ToString());
					} else if (summaryType == SummaryType.FullNames) {
						sb.Append("\n\t\t\t\t" + ((int[])formSate.advancedPatternRules[i])[0].ToString() + ", " +
												 ((int[])formSate.advancedPatternRules[i])[1].ToString());
					}
				}
			}

			return sb.ToString();
		}
	}
	
	
	
	/// <summary>
	/// Encapsulates the arguments that define a set of random numbers
	/// </summary>
	public class SetArguments {
		public int Slots;			 // The number of types in a set
		public string[] Types;		 // Types in the set
		public int SuccessionTol;	 // The mininum number of sucsessive types alowed
							
		public int[][] patternRules;
		public bool forceEqualTypes; // Determines if sets containe an equal number of each type
		
		
		public SetArguments(int slots, string[] types, int successionTol) {
			Slots = slots;
			Types = types;
			SuccessionTol = successionTol;
		}
		public SetArguments(int slots, string[] types) {
			Slots = slots;
			Types = types;
			SuccessionTol = -1;
		}
		public SetArguments(int slots) {
			Slots = slots;
			SuccessionTol = -1;
		}
		public SetArguments() {
			SuccessionTol = -1;
		}

		public int GetEveryOtherTol() {
			if (patternRules != null) {
				for (int i = 0; i < patternRules.Length; i++) {
					if (patternRules[i][0] == 2) {
						return patternRules[i][1];
					}
				}
			}
			return -1;
		}
		
		
		public override string ToString() {
			StringBuilder sb = new StringBuilder();
			// n = 10 ET   S-Tol = 3   EO-Tol = 3   AP(2,5)(3,5)(4,6)(5,6)
			string sepSpace = "   ";
			
			if (forceEqualTypes) {
				sb.Append("n = " + Slots.ToString() + " ET" + sepSpace);
			} else {
				sb.Append("n = " + Slots.ToString() + sepSpace);
			}

			if (SuccessionTol > 0) 
				sb.Append("S-Tol = " + SuccessionTol.ToString() + sepSpace);
			
			int everyOtherTol = GetEveryOtherTol();
			if (everyOtherTol > 0) 
				sb.Append("EO-Tol = " + everyOtherTol.ToString() + sepSpace);
			
			if (patternRules != null && ((everyOtherTol > 0 && patternRules.Length > 1) || (everyOtherTol == -1 && patternRules.Length > 0))) {
				sb.Append("AP");

				for (int i = 0; i < patternRules.Length; i++) {
					if (patternRules[i][0] != 2) {
						sb.Append("(" + patternRules[i][0].ToString() + "," + patternRules[i][1].ToString() + ")");
					}
				}
			}

			return sb.ToString();
		}


		// This data type function might be better in a data class
		public static SetArguments getSetArgs2(CriteriaDataSet criteriaDataSet, string criteriaID) {
			
			DataView criteriaView = new DataView(criteriaDataSet.Tables["Criteria"]);
			criteriaView.RowFilter = "CriteriaID = '" + criteriaID + "'";

			DataView typesView = new DataView(criteriaDataSet.Tables["Types"]);
			typesView.RowFilter = "CriteriaID = '" + criteriaID + "'";

			DataView patternsView = new DataView(criteriaDataSet.Tables["Patterns"]);
			patternsView.RowFilter = "CriteriaID = '" + criteriaID + "'";

			SetArguments setArgs = new SetArguments();

			// Slots and Force Equale types
			setArgs.Slots = int.Parse((string)criteriaView[0]["Slots"]);
			setArgs.forceEqualTypes = (bool)criteriaView[0]["EqualTypes"];

			// Fill Type		
			setArgs.Types = new string[typesView.Count];
			int i = 0;
			foreach (DataRowView typeRow in typesView) {
				setArgs.Types[i++] = (string)typeRow["Type"];
			}

			// SuccTol, EverOtherTol and AdvPatternRules
			ArrayList rulesAL = new ArrayList();
			foreach (DataRowView ruleRow in patternsView) {
				if ((int)ruleRow["Grouping"] == 1) {
					setArgs.SuccessionTol = (int)ruleRow["Tolerance"];
				} else if ((int)ruleRow["Tolerance"] > 0){
					rulesAL.Add(new int[2] {(int)ruleRow["Grouping"], (int)ruleRow["Tolerance"]});
				}
			}

			setArgs.patternRules = (int[][])rulesAL.ToArray(typeof(int[]));

			return setArgs;
		}

		
		public static bool ValidateSetArgs(SetArguments setArgs) {
			bool valid = true;
			if (valid && !(setArgs.Slots > 0)) valid = false;
			if (valid && !(setArgs.Types.Length >= 2)) valid = false;
			if (valid && setArgs.forceEqualTypes && !(setArgs.Slots % setArgs.Types.Length == 0)) valid = false;

			return valid;
		}
	}
}
